#pragma once

#include <stdint.h>
#include <pthread.h>

#include "../common/sti/sti.h"
#include "../common/sti/svec.h"


#define PAGE_SIZE 4096


typedef uint8_t bool;

typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;

typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;

typedef float f32;
typedef double f64;


// description of the data

typedef struct {
	u32 id;
	char* name;
	u32 offset;
	u32 len;
	
	u32 type;
	
} FieldDef;


typedef struct {
	u32 id;
	char* name;
	
	u32 fieldID;
	u32 type;
	
	u32 offset;
	u32 len;

} IndexDef;


typedef struct {
	char* name;
	u32 id;
	u32 size;	
	
	VEC(FieldDef) fields;
	VEC(IndexDef) indices;
	
} ObjDef;


// actual data storage

typedef struct Index {
	IndexDef* def;
	union {
		struct {
			HT(u64, u64) ht;
			
		} hash64;
	};
} Index;


typedef struct {
	
} ArenaInfo;


typedef struct EmptySlot {
	struct EmptySlot* next;
} EmptySlot;

typedef struct {
	u32 id;
	char* name;
	
	ObjDef* def;
	char* metaRelPath;
	char* metaAbsPath;
	
	char* backingRelPath;
	char* backingAbsPath;
	int backingFD;
	u64 fileSize;

	char* statsRelPath;
	char* statsAbsPath;
	int statsFD;
	u32 statsSize;
	
	u32 mapSize; // in bytes
	u32 mapCount; // in objects
	
	pthread_mutex_t writeLock;
	struct { // protected by write lock
		_Atomic u64 count; // TEMP transactions 
		
		void** maps;
		u64 mapsAlloc;
		u64 mapsLen;
		
		HT(u32, Index*) indices;
		
		void* stats;
	};
	
	// TODO: backing files
	// TODO: flush/sync
	// TODO: mapping of arenas
	// TODO: svec of atomic ints for tracking hot pages
	// TODO: max mapped pages
	
} ObjStore;



typedef struct {
	char* backingDir;
	
	SVEC(ObjDef) defs;
	HT(ObjDef*) defLookup;
	
	SVEC(ObjStore) stores;
	HT(u32, ObjStore*) storeLookup;
	
	
	// TODO: binlog
	// TODO: string pools
} DB;



void DB_InitEmpty(DB* db);
int ObjStore_RebuildIndex(DB* db, ObjStore* st, u32 indexIndex);

int ObjStore_ActivateMapping(DB* db, ObjStore* st, u32 mapIndex);

ObjDef* DB_AllocObjDef(DB* db, char* name);
int DB_FinalizeObjDef(DB* db, ObjDef* o);

ObjStore* DB_CreateStore(DB* db, ObjDef* o, char* name);
ObjStore* DB_LoadStore(DB* db, char* name);
void ObjStore_ReadStats(ObjStore* st);
void ObjStore_WriteStats(ObjStore* st);


int ObjStore_Insert(DB* db, ObjStore* st, void* data);
int ObjStore_IndexFetch(DB* db, ObjStore* st, u32 indexIndex, void* key, void* out);



void ObjDef_Serialize(ObjDef* def, void** pdata, u64* plen);
void ObjDef_Deserialize(ObjDef* def, void* data, u64 maxlen);
